/**
 * Copyright (c) The openTCS Authors.
 * <p>
 * This program is free software and subject to the MIT license. (For details,
 * see the licensing information (LICENSE.txt) you should have received with
 * this copy of the software.)
 */
package org.opentcs.strategies.basic.dispatching;

import org.opentcs.components.Lifecycle;
import org.opentcs.strategies.basic.dispatching.phase.AssignReservedOrdersPhase;
import org.opentcs.strategies.basic.dispatching.phase.AssignSequenceSuccessorsPhase;
import org.opentcs.strategies.basic.dispatching.phase.CheckNewOrdersPhase;
import org.opentcs.strategies.basic.dispatching.phase.FinishWithdrawalsPhase;
import org.opentcs.strategies.basic.dispatching.phase.assignment.AssignFreeOrdersPhase;
import org.opentcs.strategies.basic.dispatching.phase.assignment.AssignNextDriveOrdersPhase;
import org.opentcs.strategies.basic.dispatching.phase.parking.ParkIdleVehiclesPhase;
import org.opentcs.strategies.basic.dispatching.phase.parking.PrioritizedParkingPhase;
import org.opentcs.strategies.basic.dispatching.phase.parking.PrioritizedReparkPhase;
import org.opentcs.strategies.basic.dispatching.phase.recharging.RechargeIdleVehiclesPhase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;

import static java.util.Objects.requireNonNull;

/**
 * Performs a full dispatch run.
 *
 * @author Stefan Walter (Fraunhofer IML)
 */
public class FullDispatchTask
        implements Runnable,
        Lifecycle {

    /**
     * This class's logger.
     */
    private static final Logger LOG = LoggerFactory.getLogger(FullDispatchTask.class);

    private final CheckNewOrdersPhase checkNewOrdersPhase;
    private final FinishWithdrawalsPhase finishWithdrawalsPhase;
    private final AssignNextDriveOrdersPhase assignNextDriveOrdersPhase;
    private final AssignReservedOrdersPhase assignReservedOrdersPhase;
    private final AssignSequenceSuccessorsPhase assignSequenceSuccessorsPhase;
    private final AssignFreeOrdersPhase assignFreeOrdersPhase;
    private final RechargeIdleVehiclesPhase rechargeIdleVehiclesPhase;
    private final PrioritizedReparkPhase prioritizedReparkPhase;
    private final PrioritizedParkingPhase prioritizedParkingPhase;
    private final ParkIdleVehiclesPhase parkIdleVehiclesPhase;
    /**
     * Indicates whether this component is enabled.
     */
    private boolean initialized;

    @Inject
    public FullDispatchTask(CheckNewOrdersPhase checkNewOrdersPhase,
                            FinishWithdrawalsPhase finishWithdrawalsPhase,
                            AssignNextDriveOrdersPhase assignNextDriveOrdersPhase,
                            AssignReservedOrdersPhase assignReservedOrdersPhase,
                            AssignSequenceSuccessorsPhase assignSequenceSuccessorsPhase,
                            AssignFreeOrdersPhase assignFreeOrdersPhase,
                            RechargeIdleVehiclesPhase rechargeIdleVehiclesPhase,
                            PrioritizedReparkPhase prioritizedReparkPhase,
                            PrioritizedParkingPhase prioritizedParkingPhase,
                            ParkIdleVehiclesPhase parkIdleVehiclesPhase) {
        this.checkNewOrdersPhase = requireNonNull(checkNewOrdersPhase, "checkNewOrdersPhase");
        this.finishWithdrawalsPhase = requireNonNull(finishWithdrawalsPhase, "finishWithdrawalsPhase");
        this.assignNextDriveOrdersPhase = requireNonNull(assignNextDriveOrdersPhase,
                "assignNextDriveOrdersPhase");
        this.assignReservedOrdersPhase = requireNonNull(assignReservedOrdersPhase,
                "assignReservedOrdersPhase");
        this.assignSequenceSuccessorsPhase = requireNonNull(assignSequenceSuccessorsPhase,
                "assignSequenceSuccessorsPhase");
        this.assignFreeOrdersPhase = requireNonNull(assignFreeOrdersPhase, "assignFreeOrdersPhase");
        this.rechargeIdleVehiclesPhase = requireNonNull(rechargeIdleVehiclesPhase,
                "rechargeIdleVehiclesPhase");
        this.prioritizedReparkPhase = requireNonNull(prioritizedReparkPhase, "prioritizedReparkPhase");
        this.prioritizedParkingPhase = requireNonNull(prioritizedParkingPhase,
                "prioritizedParkingPhase");
        this.parkIdleVehiclesPhase = requireNonNull(parkIdleVehiclesPhase, "parkIdleVehiclesPhase");
    }

    @Override
    public void initialize() {
        if (isInitialized()) {
            return;
        }
        //初始化任务调度器的调度任务
        checkNewOrdersPhase.initialize();
        finishWithdrawalsPhase.initialize();
        assignNextDriveOrdersPhase.initialize();
        assignReservedOrdersPhase.initialize();
        assignSequenceSuccessorsPhase.initialize();
        assignFreeOrdersPhase.initialize();
        rechargeIdleVehiclesPhase.initialize();
        prioritizedReparkPhase.initialize();
        prioritizedParkingPhase.initialize();
        parkIdleVehiclesPhase.initialize();

        initialized = true;
    }

    @Override
    public void terminate() {
        if (!isInitialized()) {
            return;
        }

        checkNewOrdersPhase.terminate();
        finishWithdrawalsPhase.terminate();
        assignNextDriveOrdersPhase.terminate();
        assignReservedOrdersPhase.terminate();
        assignSequenceSuccessorsPhase.terminate();
        assignFreeOrdersPhase.terminate();
        rechargeIdleVehiclesPhase.terminate();
        prioritizedReparkPhase.terminate();
        prioritizedParkingPhase.terminate();
        parkIdleVehiclesPhase.terminate();

        initialized = false;
    }

    @Override
    public boolean isInitialized() {
        return initialized;
    }

    @Override
    public final void run() {

        LOG.debug("==============开始 FullDispatchTask.run ==============");
        LOG.debug("触发调度器的FullDispatchTask，执行任务分配：：： ");
        LOG.debug("Starting full dispatch run...");

        //Checks for transport orders that are still in state RAW, and attempts to prepare them for assignment.
        LOG.debug("1、检查RAW状态的订单，调整为: UNROUTABLE(router判定无法路由), ACTIVE（可路由）, DISPATCHABLE(没有其他未完成的依赖任务)");
        checkNewOrdersPhase.run();
        // Check what vehicles involved in a process should do.
        // Finishes withdrawals of transport orders after the vehicle has come to a halt.
        LOG.debug("2、处理AWAITING_ORDER的小车。如果小车身上存在WITHDRAWN的运单，则将小车(是否需要disable,需要则UNAVAILABLE否则IDLE)及运单状态(fail)做相应调整");
        finishWithdrawalsPhase.run();

        // * Assigns the next drive order to each vehicle waiting for it, or finishes the respective transport order if the vehicle has finished its last drive order.

        LOG.debug("3、分配下一个DriveOrder给AWAITING_ORDER的小车。checkForNextDriveOrder根据小车身上的TransportOrder.getCurrentDriveOrder()判断小车当前运单完成情况及是否需要分配下一个DriveOrder");
        assignNextDriveOrdersPhase.run();

        LOG.debug("4、根据order sequences分配下一个运单给小车。Assigns vehicles to the next transport orders in their respective order sequences, if any.");
        assignSequenceSuccessorsPhase.run();
        // Check what vehicles not already in a process should do.
        LOG.debug("5、分配订单给小车，首先分配已预订的订单，然后分配自由订单。Assignment of orders to vehicles.Default: Assigns reserved and then free orders to vehicles.");
        assignOrders();


        LOG.debug("6、Recharging of vehicles.Default: Sends idle vehicles with a degraded energy level to recharge locations.");
        rechargeVehicles();


        LOG.debug("7、Parking of vehicles.Default: Sends idle vehicles to parking positions.");
        parkVehicles();

        LOG.debug("Finished full dispatch run.");
        LOG.debug("==============结束 FullDispatchTask.run ==============");

    }

    /**
     * Assignment of orders to vehicles.
     * <p>
     * Default: Assigns reserved and then free orders to vehicles.
     * </p>
     */
    protected void assignOrders() {
        LOG.debug("5.1、分配已被预定的订单给小车。Assigns reserved transport orders (if any) to vehicles that have just finished their withdrawn ones.");
        assignReservedOrdersPhase.run();
        LOG.debug("5.2、分配订单给当前没有renew任务的小车。Assigns transport orders to vehicles that are currently not processing any and are not bound to any order sequences.");
        assignFreeOrdersPhase.run();
    }

    /**
     * Recharging of vehicles.
     * <p>
     * Default: Sends idle vehicles with a degraded energy level to recharge locations.
     * </p>
     */
    protected void rechargeVehicles() {

        LOG.debug("6.1、新建充电订单给Creates recharging orders for any vehicles with a degraded energy level.");
        rechargeIdleVehiclesPhase.run();
    }

    /**
     * Parking of vehicles.
     * <p>
     * Default: Sends idle vehicles to parking positions.
     * </p>
     */
    protected void parkVehicles() {
        LOG.debug("7.1、Creates parking orders for idle vehicles already at a parking position to send them to higher prioritized parking positions.");
        prioritizedReparkPhase.run();
        LOG.debug("7.2、Creates parking orders for idle vehicles not already at a parking position considering only prioritized parking positions.");
        prioritizedParkingPhase.run();
        LOG.debug("7.3、Creates parking orders for idle vehicles not already at a parking position considering all parking positions.");
        parkIdleVehiclesPhase.run();
    }
}
